package com.rpc.example.codec;

import com.rpc.example.constant.Constant;
import com.rpc.example.constant.RequestTypeEnum;
import com.rpc.example.core.Header;
import com.rpc.example.core.Protocol;
import com.rpc.example.core.Request;
import com.rpc.example.core.Response;
import com.rpc.example.serial.ISerial;
import com.rpc.example.serial.SerializeManager;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

/**
 * @author Elvis
 * @version 1.0, 2022/11/10
 */
@Slf4j
public class RpcDecode extends ByteToMessageDecoder {

    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf in, List<Object> list) throws Exception {
        log.info("+++++++++start decode ++++++++++++");

        if (in.readableBytes() < Constant.HEADER_TOTAL_LEN) {
            log.warn("报文长度小于header");
            return;
        }
        in.markReaderIndex();
        short magic = in.readShort();
        if (magic != Constant.MAGIC) {
            throw new IllegalArgumentException("Illegal magic param: " + magic);
        }
        byte serialType = in.readByte();
        byte requestType = in.readByte();
        long requestId = in.readLong();
        int dataLen = in.readInt();
        if (in.readableBytes() < dataLen) {
            in.resetReaderIndex();
        }
        Header header = Header.builder()
                .magic(magic)
                .serializeType(serialType)
                .requestType(requestType)
                .requestId(requestId)
                .dataLength(dataLen).build();
        byte[] bytes = new byte[dataLen];
        in.readBytes(bytes);
        ISerial iSerial = SerializeManager.getSerializer(serialType);
        RequestTypeEnum byCode = RequestTypeEnum.findByCode(requestType);
        switch (byCode) {
            case REQUEST:
                log.info("%%%%%%%%%%%request decode %%%%%%%%%%%%%");
                Protocol<Request> req = new Protocol<>();
                req.setHeader(header);
                Request deserialize = iSerial.deserialize(bytes, Request.class);
                req.setData(deserialize);
                list.add(req);
                break;
            case RESPONSE:
                log.info("%%%%%%%%%%%response decode %%%%%%%%%%%%%");
                Protocol<Response> resp = new Protocol<>();
                resp.setHeader(header);
                Response response = iSerial.deserialize(bytes, Response.class);
                resp.setData(response);
                list.add(resp);
                break;
            case HEARBEAT:
            default:
        }
    }
}
